-- LuaTools需要PROJECT和VERSION这两个信息
PROJECT = '	TEST'
VERSION = '1.0.0'

log.info("main", PROJECT, VERSION)

-- sys库是标配
_G.sys = require("sys")

if wdt then
    --添加硬狗防止程序卡死，在支持的设备上启用这个功能
    wdt.init(15000)--初始化watchdog设置为15s
    sys.timerLoopStart(wdt.feed, 10000)--10s喂一次狗
end
--------------------------单灯LED闪烁实验--------------------------------
--[[
local LED1 = gpio.setup(pin.PB08, 0) -- PB0输出模式
sys.taskInit(function()
    while 1 do
        log.info("LED开启")
        LED1(0)
        sys.wait(1000)
        log.info("LED关闭")
        LED1(1)
        sys.wait(1000)
    end
end)
]]--
--------------------------- 跑马灯实验-----------------------------------
--[[
-- 下面的GPIO引脚编号，请根据实际需要进行更改！
-- Air101开发板的3个LED分别为 PB08/PB09/PB10
-- Air103开发板的3个LED分别为 PB24/PB25/PB26
-- Air105开发板的3个LED分别为 PD14/PD15/PC3
local LEDA = gpio.setup(pin.PB08, 0, gpio.PULLUP) -- PB8输出模式,内部上拉
local LEDB = gpio.setup(pin.PB09, 0, gpio.PULLUP) -- PB9输出模式,内部上拉
local LEDC = gpio.setup(pin.PB10, 0, gpio.PULLUP) -- PB10输出模式,内部上拉
sys.taskInit(function()
    local count = 0
    while 1 do
        sys.wait(500)
        -- 一闪一闪亮晶晶
        LEDA(count % 3 == 0 and 1 or 0)
        LEDB(count % 3 == 1 and 1 or 0)
        LEDC(count % 3 == 2 and 1 or 0)
        log.info("gpio", "Go Go Go", count, rtos.bsp())
        count = count + 1
    end
end)
]]--
--------------------------------- 按键实验-------------------------------
--[[
local button_timer_outtime = 10 --按键定时器: 10ms
local button_shake_time = 1     --按键消抖时间: button_shake_time*button_timer_outtime
local button_long_time = 100    --按键长按时间: button_shake_time*button_timer_outtime
local button_state = 0 --按键状态（松开0，按下1）
local button_cont = 0
local LEDA = gpio.setup(pin.PB08, 0, gpio.PULLUP) -- PB8输出模式,内部上拉
button = gpio.setup(pin.PA00,	--button获取电平的闭包，button()表示状态
function()						--中断模式
	LEDA(1-gpio.get(pin.PB08))
end,
gpio.PULLUP,gpio.FALLING)  --按键按下接地，因此需要上拉
sys.taskInit(function()
    while 1 do
		if button() == 0 then   --按键当前时刻为低电平（被按下） 此处根据上下拉选择0/1
			button_cont = button_cont + 1   --计数值加一
			if button_cont > button_long_time then  --计数次数大于长按阈值
				print("long passing")
			end
		else --按键当前时刻电平与状态不符
			if button_cont < button_shake_time then  --计数次数小于抖动阈值（视为抖动）
			else
				if button_cont < button_long_time then  --计数次数小于长按阈值
					print("pass")     --正常按键情况
				else
					print("long pass")  --长按情况
				end
			end
			button_cont = 0   --计数清零
			button_state = 0  --松开状态
		end
		sys.wait(button_timer_outtime)
    end
end)
]]--

--另一种写法
--[[
button_timer = sys.timerLoopStart(function()
	if button() == 0 then   --按键当前时刻为低电平（被按下） 此处根据上下拉选择0/1
		button_cont = button_cont + 1   --计数值加一
		if button_cont > button_long_time then  --计数次数大于长按阈值
			print("long pass")
		end
	else --按键当前时刻电平与状态不符
		if button_cont < button_shake_time then  --计数次数小于抖动阈值（视为抖动）
		else
			if button_cont < button_long_time then  --计数次数小于长按阈值
				print("pass")     --正常按键情况
			else
				print("long pass......")  --长按情况
			end
		end
		button_cont = 0   --计数清零
		button_state = 0  --松开状态
	end
end,button_timer_outtime) --每次轮询间隔
]]--
------------------------------- 按键实验（V2.0）-----------------------------
--[[
local button_timer_outtime = 10 --按键定时器: 10ms
local button_shake_time = 1     --按键消抖时间: button_shake_time*button_timer_outtime
local button_long_time = 100    --按键长按时间: button_shake_time*button_timer_outtime
local button_state = 0          --按键状态（松开0，按下1）
local button_cont = 0

local count_state = false        --s是否处在两次按下间计数状态
local button_cont_release = 0    
local button_release_time = 20    --最长连按时间: button_release_time*button_timer_outtime

button = gpio.setup(pin.PA00,	--button获取电平的闭包，button()表示状态
function() end,						--中断模式
gpio.PULLUP,gpio.FALLING)  --按键按下接地，因此需要上拉

sys.taskInit(function()
    while 1 do
		if button() == 0 then   --按键当前时刻为低电平（被按下） 此处根据上下拉选择0/1
			button_cont = button_cont + 1   --计数值加一
			if button_cont > button_long_time then  --计数次数大于长按阈值
				log.info("long passing")
			end
		else --按键当前时刻电平与状态不符
			if button_cont < button_shake_time then  --计数次数小于抖动阈值（视为抖动）
                if button_cont_release > button_release_time then
                    button_cont_release = 0
                    count_state = false
                    log.info("one pass")     --正常按键情况
                end
			else
				if button_cont < button_long_time then  --计数次数小于长按阈值
                    if button_cont_release <= button_release_time and count_state == true then
                        button_cont_release = 0
                        log.info("two pass")     --按键连按情况
                    end
                    count_state = not count_state
				else
					log.info("long pass")  --长按情况
				end
			end
			button_cont = 0   --计数清零
			button_state = 0  --松开状态
            if button_cont_release <= button_release_time and count_state == true then
                button_cont_release = button_cont_release + 1   --松开计算值加一
            end
		end
		sys.wait(button_timer_outtime)
    end
end)
]]--
----------------------------PWM控制LED灯实验-----------------------------
--[[
-- Air101
-- PWM4 --> PA7
-- PWM3 --> PB3
-- PWM2 --> PB2
-- PWM1 --> PB1
-- PWM0 --> PB0
-- https:--wiki.luatos.com/api/pwm.html
sys.taskInit(function()
    while 1 do
        -- 仿呼吸灯效果（需要外接LED）
        log.info("pwm", ">>>>>")
        for i = 100,1,-1 do 
            pwm.open(4, 1000, 100-i) -- 打开PWM4, 频率1000hz, 占空比0-100
            -- pwm.open(5, 1000, 31, 0, 256) -- 打开PWM4, 频率1000Hz, 单次输出，分频（占空比）为 31/256
            sys.wait(20)
        end
        sys.wait(1000)
        for i = 100,1,-1 do 
            pwm.open(4, 1000, i)
            sys.wait(20)
        end
        sys.wait(1000)
    end
end)
]]--
--------------------------PWM控制舵机实验--------------------------------
--[[
-- SG90舵机 周期20ms  脉冲宽度0.5ms（0°）~2.5ms（180°）
-- 直接连开发板需要接5V
-- Air101不支持分频系数为1000
sys.taskInit(function()
    while 1 do
        log.info("Servo", ">>>>>")
        for i = 8,32,1 do 
            pwm.open(4, 50, i, 0 ,256) -- 打开PWM4, 频率50hz, 单次输出，分频（占空比）为 i/256
            sys.wait(20)
        end
        sys.wait(1000)
        for i = 32,8,-1 do 
            pwm.open(4, 50, i, 0 ,256) -- 打开PWM4, 频率50hz, 单次输出，分频（占空比）为 i/256
            sys.wait(20)
        end
        sys.wait(1000)
        pwm.open(4, 50, 32, 0 ,256)
        sys.wait(2000)
        pwm.open(4, 50, 8, 0 ,256)
        sys.wait(2000)
    end
end)
]]--
---------------------------UART串口实验----------------------------------
--[[
-- 实验过程：使用串口命令on/off控制LED灯的亮灭，串口接受的数据将发送返回
-- 串口库文档：https:--wiki.luatos.com/api/uart.html
local LED1 = gpio.setup(pin.PB08, 0) -- PB0输出模式

local uartid,sendQueue = 1,{}   -- 根据实际设备选取不同的uartid,串口读缓冲区

-- 串口超时，串口准备好后发布的消息
-- 例子是100ms，按需求改
local uartimeout, recvReady = 100, "UART_RECV"
--初始化
uart.setup(
    uartid,--串口id
    115200,--波特率
    8,--数据位
    1--停止位
)

uart.on(uartid, "receive", function(id, len) -- 注册串口中断服务函数，中断类型为接收中断，function内固定参数
    local s
    while true do -- 保证读完不能丢包
        s = uart.read(id, len)
        if #s == 0 then break end -- #s是取字符串的长度,等于0表示接受完成，退出
        table.insert(sendQueue, s)  -- 读取到的数据传入串口读缓冲区
    end
    sys.timerStart(sys.publish, uartimeout, recvReady)  -- 接收完成uartimeout时间后发布recvReady消息
end)

-- publish和subscribe结合使用，订阅到发布的消息后执行函数
-- 向串口发送收到的字符串
sys.subscribe(recvReady, function()      
    --拼接所有收到的数据
    local str = table.concat(sendQueue)
    -- 串口的数据读完后清空缓冲区
    sendQueue = {}
    --注意打印会影响运行速度，调试完注释掉
    --log.info("uartTask.read length", #str, str:sub(1,100))
    uart.write(uartid,str) --回复
    if str == "on" then 
        LED1(1)
    elseif str == "off" then
        LED1(0)
    end
    --在这里处理接收到的数据，这是例子
end)

-- 并非所有设备都支持sent事件(实测Air101可实现该事件中断)
uart.on(uartid, "sent", function(id)  -- 注册串口中断服务函数，中断类型为发送完成中断
    log.info("uart"..id, "sent")
end)
]]--
--------------------------------ADC实验---------------------------------
--[[
-- ADC库文档：https:--wiki.luatos.com/api/adc.html
-- Air101  输入电压范围0~2.4v
-- ADC编号   功能
--   0     ADC0->PA1  
--   1     ADC1->PA4  
--   10    CPU温度
--   11    内部电压
local adc0,adc_temp,vbat
local LED1 = gpio.setup(pin.PB08, 0) -- PB0输出模式
sys.taskInit(function()
    while 1 do
        adc.open(0)  -- 模块上的ADC0脚-PA1, 0~2.4v,不要超过范围使用!!!   返回两个int值，原始值和电压（mv）/温度值（mC）
        adc.open(10) -- CPU温度
        adc.open(11) -- VBAT电压,最新代码才支持
        sys.wait(500)

        adc0 = {adc.read(0)}
        adc_temp = {adc.read(10)}
        vbat = {adc.read(11)}

        if adc_temp[2] > 40000 then
            LED1(1)
        else
            LED1(0)
        end

        log.info("adc", "adc0: ".. (adc0[2]/1000).."V")
        log.info("adc", "temp: ".. (adc_temp[2]/1000).."°C")
        log.info("adc", "vbat: ".. (vbat[2]/1000).."V")
        -- 使用完毕后关闭,可以使得休眠电流更低.
        adc.close(0)
        adc.close(1)
        adc.close(10)
        adc.close(11)
        sys.wait(500)     
    end
end)
]]--
-------------------------I2C实验（AT24Cxx系列EEPROM)---------------------
--[[
--PA1为SCL引脚，PA4为SDA引脚
--https://blog.csdn.net/name_longming/article/details/106151754
--https://blog.csdn.net/u013427264/article/details/42708855?spm=1001.2101.3001.6650.2&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-2.pc_relevant_default&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-2.pc_relevant_default
--注意I2C地址为七位地址
local AT24C02_ADDRESS   =   0x50   --A0，A1，A2接地为0，地址为1010 000 所以芯片选址为0x50
sys.taskInit(function()
    -- 初始化i2c，使用id为0
    if i2c.setup(0, i2c.FAST, AT24C02_ADDRESS) == 1 then     
        log.info("存在 i2c0")
    else
        i2c.close(0) -- 关掉
    end
    local addr = 0x05  -- AT24C02是一个2K位串行CMOS E2PROM，内部含有256个8位字节 地址0x00-0xFF
    local i = 0x01
    while 1 do
        log.info("写入：", i2c.writeReg(0, AT24C02_ADDRESS, addr, string.char(i, i+1)))  --写入两个字节 最多一次7个
        log.info("写入的值为", i,i+1)
        sys.wait(1000) -- 等待延时
        log.info("读取的数为：", (i2c.readReg(0, AT24C02_ADDRESS, addr, 2)):toHex()) -- 打印读取数据采集结果 读两个字节
        sys.wait(1000)
    end
end)
]]--
-------------------------I2C实验（AHT20+BMP280库实现)--------------------
--[[ 
local bmx = require "bmx"
i2cid = 0
--i2c_speed = i2c.SLOW
i2c_speed = i2c.FAST
sys.taskInit(function()
    i2c.setup(i2cid,i2c_speed)
    bmx.init(i2cid)--初始化,传入i2c_id
    while 1 do
        local bmx_data = bmx.get_data()
        if bmx_data.hum then
            log.info("bmp180湿度:"..(bmx_data.hum).."%")       --bmp180不支持
        end
        if bmx_data.temp then
            log.info("bmp180温度:"..(bmx_data.temp).."℃")
        end
        if bmx_data.press then
            log.info("bmp180气压:"..(bmx_data.press).."hPa")
        end
        if bmx_data.high then
            log.info("bmp180高度:"..(bmx_data.high).."m")
        end
        log.info("--------------------------------")
        sys.wait(1000)
    end
end)


local aht10 = require "aht10"    --AHT20可以用AHT10的这个，但实际有出入的,20初始化指令为BE，10初始化指令为0xE1（aht10.lua中修改该处即可）
--i2cid = 0
--i2c_speed = i2c.FAST
sys.taskInit(function()
    i2c.setup(i2cid,i2c_speed)
    aht10.init(i2cid)--初始化,传入i2c_id
    while 1 do
        local aht10_data = aht10.get_data()
        log.info("AHT20湿度:"..(aht10_data.RH*100).."%")
        log.info("AHT20温度:"..(aht10_data.T).."℃")
        sys.wait(1000)
    end
end) 
]]--
------------------------------I2C实验（AHT20温湿度)----------------------
--[[
--https://zhuanlan.zhihu.com/p/312206749
--初始化命令 ('1011’1110') ，即0xBE；
--测量温湿度命令('1010’1100')，即0xAC；
--软复位命令('1011’1010')，即0xBA。
--AHT20_DEVICE_ADDR   0x38
--AHT20_READ_ADDR     ((0x38<<1)|0x1)
--AHT20_WRITE_ADDR    ((0x38<<1)|0x0)

--此处没有使用状态位，若使用以保证正常运行可参照aht10.lua文件
local AHT20_ADDRESS           =   0x38
---器件所用地址
local AHT20_INIT                  =   0xBE --初始化命令
local AHT20_MEASURE               =   0xAC --触发测量命令
local AHT20_SOFT_RESET            =   0xBA --软复位命令,软复位所需时间不超过20毫秒.
local AHT20_STATE                 =   0x71 --状态字.详见文档

local raw_data={Srh=nil,St=nil}
local aht20_data={RH=nil,T=nil}

sys.taskInit(function()
    -- 初始化i2c，使用id为0
    if i2c.setup(0, i2c.FAST, AHT10_ADDRESS) == 1 then     
        log.info("存在 i2c0")
    else
        i2c.close(0) -- 关掉
    end
    sys.wait(40)--40 毫秒等待设备稳定
    i2c.send(0, AHT20_ADDRESS, AHT20_SOFT_RESET)--软复位
    sys.wait(20)
    i2c.send(0, AHT20_ADDRESS, string.char(AHT20_INIT)) -- 发送初始化命令
    while 1 do
        i2c.send(0, AHT20_ADDRESS, {AHT20_MEASURE, 0x33, 0x00})  --直接发送 0xAC命令(触发测量)，此命令参数有两个字节，第一个字节为 0x33，第二个字节为0x00
        sys.wait(80)--等待80毫秒以上保证测量完成，状态位忙状态Bit[7]为0，然后可以读取六个字节(发0X71即可以读取)。
        local data = i2c.recv(0, AHT20_ADDRESS, 6) -- 从i2c0读取6个字节的数据
        local _, data1, data2, data3, data4, data5, data6 = pack.unpack(data, "b6")  --解包为6个字符型
        
        raw_data.Srh = bit.bor(bit.bor(bit.rshift(data4, 4), bit.lshift(data3, 4)),bit.lshift(data2, 12))   --湿度获取原始值
        raw_data.St = bit.bor(bit.bor(bit.lshift(bit.band(data4, 0x0f), 16), bit.lshift(data5, 8)), data6)   --温度获取原始值

        aht20_data.RH = raw_data.Srh/1048576     --湿度计算值
        aht20_data.T = raw_data.St/1048576*200-50   --温度计算值
        log.info("温度为："..(aht20_data.RH*100).."%","温度为"..(aht20_data.T).."℃")
        sys.wait(500)
    end
end)
]]--
-----------------------------I2C实验（MPU6050库方法)---------------------
--[[
--PA1为SCL引脚，PA4为SDA引脚
--需要添加mpu6xxx.lua文件
--库内容：https:--gitee.com/openLuat/LuatOS/blob/master/script/libs/mpu6xxx/mpu6xxx.lua
--支持mpu6500,mpu6050,mpu9250,icm2068g,icm20608d,自动判断器件id,只需要配置i2c id就可以
--注意:因使用了sys.wait()所有api需要在协程中使用
local mpu6xxx = require "mpu6xxx"
i2cid = 0
i2c_speed = i2c.FAST
sys.taskInit(function()
    i2c.setup(i2cid,i2c_speed)
    mpu6xxx.init(i2cid)--初始化,传入i2c_id
    while 1 do
        sys.wait(100)
        local temp = mpu6xxx.get_temp()--获取温度
        log.info("6050temp", temp)
        local accel = mpu6xxx.get_accel()--获取加速度 单位: mg
        log.info("6050accel", "accel.x",accel.x,"accel.y",accel.y,"accel.z",accel.z)
        local gyro = mpu6xxx.get_gyro()--获取陀螺仪 deg / 10s
        log.info("6050gyro", "gyro.x",gyro.x,"gyro.y",gyro.y,"gyro.z",gyro.z)
    end
end)
]]--
-----------------------------I2C实验(mp6050)----------------------------
--[[
--尚未实现姿态结算方面的功能（DMP能力不足，无法实现,以下代码也仍存在问题）
local Kp = 10.0                         --这里的KpKi是用于调整加速度计修正陀螺仪的速度
local Ki = 0.008
local halfT = 0.1                     --采样周期的一半，用于求解四元数微分方程时计算角增量
local q0, q1, q2, q3 = 1, 0, 0, 0       --初始姿态四元数，由变换四元数公式得来
local exInt, eyInt, ezInt = 0, 0, 0     --当前加计测得的重力加速度在三轴上的分量
local Q_ANGLE = {X = nil, Y= nil, Z= nil}
local GYRO_I = {X = 0, Y= 0, Z= 0}

function IMUupdate( gx,  gy,  gz,  ax,  ay,  az) --g表陀螺仪，a表加计
    local q0temp,q1temp,q2temp,q3temp       --四元数暂存变量，求解微分方程时要用
    local norm                              --矢量的模或四元数的范数
    local vx, vy, vz                        --当前姿态计算得来的重力在三轴上的分量
    local ex, ey, ez                        --当前加计测得的重力加速度在三轴上的分量
                                            --与用当前姿态计算得来的重力在三轴上的分量的误差
    -- 先把这些用得到的值算好
    local q0q0 = q0*q0
    local q0q1 = q0*q1
    local q0q2 = q0*q2
    local q1q1 = q1*q1
    local q1q3 = q1*q3
    local q2q2 = q2*q2
    local q2q3 = q2*q3
    local q3q3 = q3*q3      
    if(ax*ay*az==0) then--加计处于自由落体状态时不进行姿态解算，因为会产生分母无穷大的情况
        return
    end
    norm = math.sqrt(ax*ax + ay*ay + az*az)--单位化加速度计，
    ax = ax /norm-- 这样变更了量程也不需要修改KP参数，因为这里归一化了
    ay = ay / norm
    az = az / norm
    --用当前姿态计算出重力在三个轴上的分量，
    --参考坐标n系转化到载体坐标b系的用四元数表示的方向余弦矩阵第三列即是（博文一中有提到）
    vx = 2*(q1q3 - q0q2)        
    vy = 2*(q0q1 + q2q3)
    vz = q0q0 - q1q1 - q2q2 + q3q3 
    --计算测得的重力与计算得重力间的误差，向量外积可以表示这一误差
    --原因我理解是因为两个向量是单位向量且sin0等于0
    --不过要是夹角是180度呢~这个还没理解
    ex = (ay*vz - az*vy)                                                                   
    ey = (az*vx - ax*vz) 
    ez = (ax*vy - ay*vx) 

    exInt = exInt + ex * Ki     --对误差进行积分
    eyInt = eyInt + ey * Ki
    ezInt = ezInt + ez * Ki
    -- adjusted gyroscope measurements
    gx = gx + Kp*ex + exInt     --将误差PI后补偿到陀螺仪，即补偿零点漂移
    gy = gy + Kp*ey + eyInt
    gz = gz + Kp*ez + ezInt     --这里的gz由于没有观测者进行矫正会产生漂移，表现出来的就是积分自增或自减
    -- 陀螺仪积分
    GYRO_I.X = GYRO_I.X + halfT*2*gx
    GYRO_I.Y = GYRO_I.Y + halfT*2*gy
    GYRO_I.Z = GYRO_I.Z + halfT*2*gz
    --下面进行姿态的更新，也就是四元数微分方程的求解
    q0temp=q0                   --暂存当前值用于计算
    q1temp=q1                   --网上传的这份算法大多没有注意这个问题，在此更正
    q2temp=q2
    q3temp=q3
    --采用一阶毕卡解法，相关知识可参见《惯性器件与惯性导航系统》P212
    q0 = q0temp + (-q1temp*gx - q2temp*gy -q3temp*gz)*halfT
    q1 = q1temp + (q0temp*gx + q2temp*gz -q3temp*gy)*halfT
    q2 = q2temp + (q0temp*gy - q1temp*gz +q3temp*gx)*halfT
    q3 = q3temp + (q0temp*gz + q1temp*gy -q2temp*gx)*halfT
    --单位化四元数在空间旋转时不会拉伸，仅有旋转角度，这类似线性代数里的正交变换
    norm = math.sqrt(q0*q0 + q1*q1 + q2*q2 + q3*q3)
    q0 = q0 / norm
    q1 = q1 / norm
    q2 = q2 / norm
    q3 = q3 / norm
    --四元数到欧拉角的转换，公式推导
    --其中YAW航向角由于加速度计对其没有修正作用，因此此处直接用陀螺仪积分代替
    Q_ANGLE.Z = GYRO_I.Z  -- yaw(还存在问题)
    Q_ANGLE.Y = math.asin(-2 * q1 * q3 + 2 * q0* q2)*57.3 -- pitch
    Q_ANGLE.X = math.atan2(2 * q2 * q3 + 2 * q0 * q1,-2 * q1 * q1 - 2 * q2* q2 + 1)* 57.3 -- roll
end

local i2cslaveaddr = 0x68  -- mpu6050 AD0引脚不接通信地址默认为0x68
local i2cid = 0    -- 初始化i2c，使用设备id为0(id可以自己定义)
local buffer     --读取数值
local temp       --温度
local accel={x=nil,y=nil,z=nil}   --加速度
local gyro={x=nil,y=nil,z=nil}    --陀螺仪

-- MPU6050数值转换系数
local MPU6050_ACCEL_SEN           =   16384
local MPU6050_GYRO_SEN            =   1310
local MPU6050_TEMP_SEN            =   340
local MPU6050_TEMP_OFFSET         =   36.5

-- MPU6050数据寄存器地址（查手册）
local MPU6050_RA_ACCEL_XOUT_H     =   0x3B
local MPU6050_RA_ACCEL_XOUT_L     =   0x3C
local MPU6050_RA_ACCEL_YOUT_H     =   0x3D
local MPU6050_RA_ACCEL_YOUT_L     =   0x3E
local MPU6050_RA_ACCEL_ZOUT_H     =   0x3F
local MPU6050_RA_ACCEL_ZOUT_L     =   0x40
local MPU6050_RA_TEMP_OUT_H       =   0x41
local MPU6050_RA_TEMP_OUT_L       =   0x42
local MPU6050_RA_GYRO_XOUT_H      =   0x43
local MPU6050_RA_GYRO_XOUT_L      =   0x44
local MPU6050_RA_GYRO_YOUT_H      =   0x45
local MPU6050_RA_GYRO_YOUT_L      =   0x46
local MPU6050_RA_GYRO_ZOUT_H      =   0x47
local MPU6050_RA_GYRO_ZOUT_L      =   0x48

-- MPU6050配置寄存器地址（查手册）
local MPU6050_RA_PWR_MGMT_1     =   0x6B	--电源管理，典型值：0x00(正常启用)
local MPU6050_RA_SMPLRT_DIV		=   0x19	--陀螺仪采样率，典型值：0x07(125Hz)
local MPU6050_RA_CONFIG			=   0x1A	--低通滤波频率，典型值：0x06(5Hz)
local MPU6050_RA_GYRO_CONFIG	=   0x1B	--陀螺仪自检及测量范围，典型值：0x18(不自检，2000deg/s)
local MPU6050_RA_ACCEL_CONFIG	=   0x1C	--加速计自检、测量范围及高通滤波频率，典型值：0x01(不自检，2G，5Hz)
local MPU6050_RA_FIFO_EN        =   0x23    --fifo使能
local MPU6050_RA_INT_PIN_CFG    =   0x37    --int引脚有效电平
local MPU6050_RA_INT_ENABLE     =   0x38    --中断使能
local MPU6050_RA_USER_CTRL      =   0x6A    --MPU6050的主/从机模式，典型值：0x00(从机模式)
local MPU6050_RA_PWR_MGMT_1     =   0x6B
local MPU6050_RA_PWR_MGMT_2     =   0x6C

sys.taskInit(function()
    -- 初始化i2c，setup用的是开发板上的i2c引脚，也可以通过i2c.createSoft创建软件i2c对象
    if i2c.setup(i2cid, i2c.FAST, i2cslaveaddr) == 1 then   
        log.info("i2c"..i2cid.." exist")    
    else
        i2c.close(i2cid) -- 关掉
    end

    -- 初始化mpu6050
    i2c.send(i2cid, i2cslaveaddr, {MPU6050_RA_PWR_MGMT_1, 0x80})    --复位
    sys.wait(100)
    i2c.send(i2cid, i2cslaveaddr, {MPU6050_RA_PWR_MGMT_1, 0x00})    --唤醒
    sys.wait(100)
    i2c.send(i2cid, i2cslaveaddr, {MPU6050_RA_SMPLRT_DIV, 0x07})    --陀螺仪采样率，典型值：0x07(125Hz)
    i2c.send(i2cid, i2cslaveaddr, {MPU6050_RA_CONFIG, 0x06})        --低通滤波频率，典型值：0x06(5Hz)
    i2c.send(i2cid, i2cslaveaddr, {MPU6050_RA_GYRO_CONFIG, 0x18})   --陀螺仪自检及测量范围，典型值：0x18(不自检，2000deg/s)
    i2c.send(i2cid, i2cslaveaddr, {MPU6050_RA_ACCEL_CONFIG, 0x01})  --加速计自检、测量范围及高通滤波频率，典型值：0x01(不自检，2G，5Hz)
    --i2c.send(i2cid, i2cslaveaddr, {MPU6050_RA_FIFO_EN, 0x78})     --打开陀螺仪和加速计fifo
    --i2c.send(i2cid, i2cslaveaddr, {MPU6050_RA_INT_ENABLE, 0x00})  --关闭所有中断
    --i2c.send(i2cid, i2cslaveaddr, {MPU6050_RA_USER_CTRL, 0x00})   --I2C主模式关闭
    i2c.send(i2cid, i2cslaveaddr, {MPU6050_RA_PWR_MGMT_1, 0x01})    --设置x轴的pll为参考
    i2c.send(i2cid, i2cslaveaddr, {MPU6050_RA_PWR_MGMT_2, 0x00})    --加速度计与陀螺仪开启
    log.info("mpu6050 init_ok")

    while 1 do
        sys.wait(halfT*2000)

        --温度原始数据获取 
        i2c.send(i2cid, i2cslaveaddr,MPU6050_RA_TEMP_OUT_H)         --获取温度的地址
        buffer = i2c.recv(i2cid, i2cslaveaddr, 2)                   --获取2字节数据
        _, temp = pack.unpack(buffer, ">h")                         --将字符串解包成大端编码short (2字节)
        --计算温度的数据 单位：°C
        temp = temp / MPU6050_TEMP_SEN + MPU6050_TEMP_OFFSET
        log.info("6050temp", temp)

        --陀螺仪测角速度的，加速度传感器测角加速度的，二者数据通过算法就可以得到PITCH、YAW、ROLL角

        --加速度原始数据获取 
        i2c.send(i2cid, i2cslaveaddr,MPU6050_RA_ACCEL_XOUT_H)       --获取X方向加速度的地址
        buffer = i2c.recv(i2cid, i2cslaveaddr, 2)                   
        _,accel.x = pack.unpack(buffer,">h")
        i2c.send(i2cid, i2cslaveaddr,MPU6050_RA_ACCEL_YOUT_H)       --获取Y方向加速度的地址
        buffer = i2c.recv(i2cid, i2cslaveaddr, 2)                   
        _,accel.y = pack.unpack(buffer,">h")
        i2c.send(i2cid, i2cslaveaddr,MPU6050_RA_ACCEL_ZOUT_H)       --获取Z方向加速度的地址
        buffer = i2c.recv(i2cid, i2cslaveaddr, 2)                   
        _,accel.z = pack.unpack(buffer,">h")
        --计算加速度计的数据 单位: mg
        accel.x = accel.x*1000/MPU6050_ACCEL_SEN
        accel.y = accel.y*1000/MPU6050_ACCEL_SEN
        accel.z = accel.z*1000/MPU6050_ACCEL_SEN
        log.info("6050accel", "accel.x",accel.x,"accel.y",accel.y,"accel.z",accel.z)

        --陀螺仪原始数据获取 
        i2c.send(i2cid, i2cslaveaddr,MPU6050_RA_GYRO_XOUT_H)        --获取X方向陀螺仪的地址
        buffer = i2c.recv(i2cid, i2cslaveaddr, 2)
        _,gyro.x = pack.unpack(buffer,">h")
        i2c.send(i2cid, i2cslaveaddr,MPU6050_RA_GYRO_YOUT_H)        --获取Y方向陀螺仪的地址
        buffer = i2c.recv(i2cid, i2cslaveaddr, 2)
        _,gyro.y = pack.unpack(buffer,">h")
        i2c.send(i2cid, i2cslaveaddr,MPU6050_RA_GYRO_ZOUT_H)        --获取Z方向陀螺仪的地址
        buffer = i2c.recv(i2cid, i2cslaveaddr, 2)
        _,gyro.z = pack.unpack(buffer,">h")
        --计算陀螺仪的数据 单位：deg/10s
        gyro.x = gyro.x*100/MPU6050_GYRO_SEN
        gyro.y = gyro.y*100/MPU6050_GYRO_SEN
        gyro.z = gyro.z*100/MPU6050_GYRO_SEN
        log.info("6050gyro", "gyro.x",gyro.x,"gyro.y",gyro.y,"gyro.z",gyro.z)
        
        --位姿解算
        IMUupdate(gyro.x/10,gyro.y/10,gyro.z/10,accel.x,accel.y,accel.z)
        log.info("6050angle", "Q_ANGLE.X",Q_ANGLE.X,"Q_ANGLE.Y",Q_ANGLE.Y,"Q_ANGLE.Z",Q_ANGLE.Z)
    end
end)
]]--
-----------------------------LCD屏测试----------------------------------
--[[
--屏幕初始化
--SCL->PB2  SDA->PB5  RES->PB3
--DC->PB1  CS->PB4  BL->PB0

local spi_lcd = spi.deviceSetup(0, pin.PB04, 0, 0, 8, 2000000, spi.MSB, 1, 1)
log.info(
    "lcd.init",
    lcd.init(
        "st7789",
        {
            port = "device",
            pin_dc = pin.PB01,
            pin_pwr = pin.PB00,
            pin_rst = pin.PB03,
            direction = 0,
            w = 240,
            h = 320,
            xoffset = 0,
            yoffset = 0
        },
        spi_lcd
    )
)
sys.taskInit(function()
    local buff = zbuff.create({141,21,16},0x105F)  -- lcd颜色填充
    log.info("lcd", "size", lcd.getSize())   --获得屏幕尺寸
    while 1 do
        log.info("lcd.setColor", lcd.setColor(0xFFFF,0x0000)) -- lcd颜色设置（背景色，前景色）
        log.info("lcd.drawPoint", lcd.drawPoint(120,10,0x001F))    -- 画一个点（点x/y; 绘画颜色:可选参数,默认前景色）
        sys.wait(1000)
        log.info("lcd.drawLine", lcd.drawLine(20,20,220,20,0x010F))  --画线 (两点x/y; 绘画颜色:可选参数,默认前景色)
        sys.wait(1000)
        log.info("lcd.drawRectangle", lcd.drawRectangle(20,30,100,70,0xF800))  --画框（左上x/y; 右下x/y; 绘画颜色:可选参数,默认前景色）
        sys.wait(1000)
        log.info("lcd.drawCircle", lcd.drawCircle(180,50,20,0x0CE0))   --画圆（圆心x/y; 半径; 绘画颜色:可选参数,默认前景色）
        sys.wait(1000)
        log.info("lcd.draw", lcd.draw(50,80,190,100,buff))             --左上x/y; 右下x/y; 字符串或buff对象
        sys.wait(1000)
        log.info("lcd.fill",lcd.fill(50,110,190,130,0x0F0F))  -- lcd颜色填充（左上x/y; 右下x/y; 绘画颜色:可选参数,默认背景色）
        sys.wait(1000)
        log.info("lcd.setFont", lcd.setFont(lcd.font_opposansm16))  --设置为字体,对之后的drawStr有效,调用lcd.drawStr前一定要先设置; 使用中文字体需在luat_conf_bsp.h中开启相对应的宏
        log.info("lcd.drawStr", lcd.drawStr(90,155,"TEST"))     --左下角x/y; 内容; str颜色 注意:此参数可选，如不填写则使用之前设置的颜色，绘制只会绘制字体部分，背景需要自己清除。
        sys.wait(1000)
        log.info("lcd.drawQrcode",lcd.drawQrcode(110,170,"https://www.buaa.edu.cn/",1))  --缓冲区绘制QRCode(x/y坐标; 二维码内容; 显示大小：可选，不可小于21,默认21)
        sys.wait(1000)
        log.info("lcd.drawXbm",lcd.drawXbm(112, 200, 16,16, string.char(        -- 取模使用PCtoLCD2002软件即可 在(0,0)为左上角,绘制 16x16 "今" 的位图
            0x80,0x00,0x80,0x00,0x40,0x01,0x20,0x02,0x10,0x04,0x48,0x08,0x84,0x10,0x83,0x60,
            0x00,0x00,0xF8,0x0F,0x00,0x08,0x00,0x04,0x00,0x04,0x00,0x02,0x00,0x01,0x80,0x00
        )))
        sys.wait(1000)
        if lcd.showImage then
            log.info("lcd.showImage",lcd.showImage(0,0,"/luadb/logo.jpg"))   --显示图片 Air101不适用
            sys.wait(1000)
        end
        log.info("lcd.off",lcd.off())  -- 关闭lcd显示屏背光
        sys.wait(1000)
        log.info("lcd.on",lcd.on())   -- 开启lcd显示屏背光
        sys.wait(1000)
        log.info("lcd.invon",lcd.invoff())   --lcd反显关闭
        sys.wait(1000)
        log.info("lcd.invoff",lcd.invon())  --lcd反显开启(默认开启)
        sys.wait(1000)
        log.info("lcd.clear",lcd.clear())  -- lcd清屏（屏幕颜色:可选参数,默认背景色）
        sys.wait(1000)
    end
end)
]]--
-------------------------------LVGL实验---------------------------------
--[[ --屏幕初始化
local spi_lcd = spi.deviceSetup(0, pin.PB04, 0, 0, 8, 2000000, spi.MSB, 1, 1)
log.info(
    "lcd.init",
    lcd.init(
        "st7789",
        {
            port = "device",
            pin_dc = pin.PB01,
            pin_pwr = pin.PB00,
            pin_rst = pin.PB03,
            direction = 0,
            w = 240,
            h = 320,
            xoffset = 0,
            yoffset = 0
        },
        spi_lcd
    )
)

sys.taskInit(function()
    lcd.invoff()
    log.info("lvgl", lvgl.init())           --lvgl初始化
    lvgl.disp_set_bg_color(nil, 0xFFFFFF)   --设置页面背景色

    local scr = lvgl.obj_create(nil, nil)   --创建屏幕（画布）


    local btn = lvgl.btn_create(scr)        --创建按钮
    local btn1 = lvgl.btn_create(scr)       --创建按钮

    -- 位置、大小、布局：http://lvgl.100ask.net/8.2/overview/coords.html#simple-way
    -- C:\Users\YUE\Desktop\MyLuatOS\LuatOS\components\lvgl\binding
    -- C:\Users\YUE\Desktop\MyLuatOS\LuatOS\components\lvgl\src\lv_core\lv_obj.h

    -- 坐标位置
    --lvgl.obj_set_x(btn1, 10)
    --lvgl.obj_set_y(btn1, 20)
    lvgl.obj_set_pos(btn1, 20, 40)
    -- x 和 y 坐标是从父内容区域的左上角开始测量的

    -- 对齐（align）
    lvgl.obj_align(btn, scr, lvgl.ALIGN_CENTER, 0, -40)  --按键对齐到屏幕中间
    -- lvgl.scr_act():获取默认显示的活动屏幕，此处可代替scr
    -- 可取以下对齐选项 C:\Users\YUE\Desktop\MyLuatOS\LuatOS\components\lvgl\gen\luat_lv_enum.h
    -- ALIGN_*_TOP_LEFT  ALIGN_*_TOP_MID  ALIGN_TOP_*_RIGHT    
    -- ALIGN_*_LEFT_MID  ALIGN_CENTER  ALIGN_*_RIGHT_MID
    -- ALIGN_*_BOTTOM_LEFT  ALIGN_*_BOTTOM_MID ALIGN_*_BOTTOM_RIGHT
    -- * 为 IN 或 OUT
    -- 0, 0 表示x、y轴的偏移量均为0

    -- 大小（size）
    --lvgl.obj_set_width(btn1, 200)   
    --lvgl.obj_set_height(btn1, 100)
    lvgl.obj_set_size(btn1, 200, 50)   -- 宽度、高度像素大小

    -- 样式使用（style）
    -- 位置、大小和对齐属性是样式属性。
    -- 该部分还没移植好

    -- 创建标签
    local label = lvgl.label_create(btn)
    local label1 = lvgl.label_create(btn1)
    lvgl.label_set_text(label, "LuatOS!")  --按钮内容
    lvgl.label_set_text(label1, "BUAA & TJ")  --按钮内容



    --组件在：C:\Users\YUE\Desktop\MyLuatOS\LuatOS\components\lvgl\gen\lv_widgets 

    --创建进度条
    local bar = lvgl.bar_create(scr)
    lvgl.obj_set_size(bar, 200, 20)
    lvgl.obj_align(bar, scr, lvgl.ALIGN_IN_TOP_MID, 0, 10)  



    -- 回调函数
    slider_event_cb = function(obj, event)
        if event == lvgl.EVENT_VALUE_CHANGED then 
            local val = (lvgl.slider_get_value(obj) or "0").."%"
            lvgl.label_set_text(slider_label, val)
            lvgl.obj_align(slider_label, obj, lvgl.ALIGN_OUT_BOTTOM_MID, 0, 10)
        end
    end

    -- 创建滑动条
    slider = lvgl.slider_create(scr, nil)
    lvgl.obj_set_size(slider, 200, 20)
    lvgl.obj_align(slider, scr, lvgl.ALIGN_CENTER, 0, 0)
    lvgl.obj_set_event_cb(slider, slider_event_cb)

    -- 创建标签
    slider_label = lvgl.label_create(slider)
    lvgl.label_set_text(slider_label, "0%")
    lvgl.obj_align(slider_label, slider, lvgl.ALIGN_OUT_BOTTOM_MID, 0, 10)


    -- style = lvgl.style_create()
    -- lvgl.style_init(style)
    -- --lvgl.style_set_radius(style, lvgl.STATE_DEFAULT, 20)
    -- lvgl.style_set_bg_color(style, lvgl.STATE_DEFAULT, 0xff9e)

    -- --创建一个 Arc
    -- arc = lvgl.arc_create(scr)
    -- --设置 Arc 的大小
    -- lvgl.obj_set_size(arc, 150, 150)
    -- --设置Arc到 0 度位置的偏移量
    -- lvgl.arc_set_rotation(arc, 135)
    -- --设置Arc背景角度范围
    -- lvgl.arc_set_bg_angles(arc, 0, 270)
    -- --设置Arc设定值
    -- lvgl.arc_set_value(arc, 40)
    -- --设置 Arc 的位置
    -- lvgl.obj_align(arc, scr, lvgl.ALIGN_CENTER, 0, 100)
    -- lvgl.obj_add_style(arc, lvgl.ARC_PART_BG, style)



    set_angle = function(obj, value)
        lv_arc_set_value(obj, value)
    end

    arc1 = lvgl.arc_create(scr)
    lvgl.arc_set_rotation(arc1, 270)
    lvgl.arc_set_bg_angles(arc1, 0, 360)
    lvgl.obj_remove_style(arc1, lvgl.ARC_PART_KNOB)   --Be sure the knob is not displayed
    --lvgl.obj_clear_flag(arc1, lvgl.OBJ_FLAG_CLICKABLE)  --To not allow adjusting by click
    lvgl.obj_align(arc1, scr, lvgl.ALIGN_CENTER, 0, 100)
    
    anim = lvgl.anim_create()
    lvgl.anim_init(anim)
    lvgl.anim_set_var(anim, arc1)
    lvgl.anim_set_exec_cb(anim, set_angle)
    lvgl.anim_set_time(anim, 1000);
    lvgl.anim_set_repeat_count(anim, 100)   --Just for the demo
    lvgl.anim_set_repeat_delay(anim, 500);
    lvgl.anim_set_values(anim, 0, 100);
    lvgl.anim_start(anim);
    
    lvgl.scr_load(scr)
end) 
]]--
--------------------------tm1637数码管显示实验---------------------------
--实现原理：数码管每一秒变化计时一次，短按下boot按键开始计时，再次短按下结束计时，长按重新计时
--CLK <-> PA0   DIO <-> PA4
--[[
local tm1637 = require "tm1637"
local i1,i2,i3,i4
local ps = true
local cs = false   --计数状态
local rs = false   --重新计数状态

sys.taskInit(function()
    tm1637.init(1,4)
    while 1 do
        i1=0
        while i1<=5 do
            i2=0
            while i2<=9 do
                i3=0
                while i3<=5 do
                    i4=0
                    while i4 <= 9 do
                        if rs == true then
                            i1,i2,i3,i4=0,0,0,0
                            tm1637.singleShow(0,i1)
                            tm1637.singleShow(1,i2,true)
                            tm1637.singleShow(2,i3)
                            tm1637.singleShow(3,i4)
                            cs = false
                            rs = false
                        else
                            if cs == true then
                                tm1637.singleShow(0,i1)
                                tm1637.singleShow(1,i2,ps)
                                tm1637.singleShow(2,i3)
                                tm1637.singleShow(3,i4)
                                sys.wait(382)
                                ps = not ps
                                tm1637.singleShow(1,i2,ps)
                                sys.wait(618)
                                ps = not ps
                                i4 = i4 + 1
                            else
                                sys.wait(10)
                            end    
                        end
                    end
                    i3=i3+1
                end
                i2=i2+1
            end
            i1=i1+1
        end
    end
end)

local button_timer_outtime = 10 --按键定时器: 10ms
local button_shake_time = 1     --按键消抖时间: button_shake_time*button_timer_outtime
local button_long_time = 100    --按键长按时间: button_shake_time*button_timer_outtime
local button_state = 0 --按键状态（松开0，按下1）
local button_cont = 0

button = gpio.setup(pin.PA00,	--button获取电平的闭包，button()表示状态
                    function() end,						
                    gpio.PULLUP,gpio.FALLING)  --中断模式 --按键按下接地，因此需要上拉

sys.taskInit(function()
    while 1 do
		if button() == 0 then   --按键当前时刻为低电平（被按下） 此处根据上下拉选择0/1
			button_cont = button_cont + 1   --计数值加一
            if button_cont > button_long_time then  --计数次数大于长按阈值
				rs = true
			end
		else --按键当前时刻电平与状态不符
			if button_cont < button_shake_time then  --计数次数小于抖动阈值（视为抖动）
			else
				if button_cont < button_long_time then  --计数次数小于长按阈值
					cs = not cs     --正常按键情况
				else
                    rs = true       --长按情况
				end
			end
			button_cont = 0   --计数清零
			button_state = 0  --松开状态
		end
		sys.wait(button_timer_outtime)
    end
end)
]]--
--------------------------tm1637数码管显示实验（V2.0）-------------------
--[[
--实现原理：数码管每一秒变化计时一次，短按下boot按键开始计时，再次短按下结束计时，长按重新计时,连按两下熄屏
local tm1637 = require "tm1637"
local i1,i2,i3,i4
local ps = true
local cs = false   --计数状态
local rs = false   --重新计数状态
local ss = true    --显示状态

sys.taskInit(function()
    tm1637.init(1,4)
    while 1 do
        i1=0
        while i1<=5 do
            i2=0
            while i2<=9 do
                i3=0
                while i3<=5 do
                    i4=0
                    while i4 <= 9 do
                        if ss == true then
                            if cs == true then
                                i1,i2,i3,i4=0,0,0,0
                                tm1637.singleShow(0,i1)
                                tm1637.singleShow(1,i2,true)
                                tm1637.singleShow(2,i3)
                                tm1637.singleShow(3,i4)
                                cs = false
                                rs = false
                                ss = false
                            else
                                tm1637.clear()
                                sys.wait(10)
                            end
                        elseif rs == true then
                            i1,i2,i3,i4=0,0,0,0
                            tm1637.singleShow(0,i1)
                            tm1637.singleShow(1,i2,true)
                            tm1637.singleShow(2,i3)
                            tm1637.singleShow(3,i4)
                            cs = false
                            rs = false
                        else
                            if cs == true then
                                tm1637.singleShow(0,i1)
                                tm1637.singleShow(1,i2,ps)
                                tm1637.singleShow(2,i3)
                                tm1637.singleShow(3,i4)
                                sys.wait(382)
                                ps = not ps
                                tm1637.singleShow(1,i2,ps)
                                sys.wait(618)
                                ps = not ps
                                i4 = i4 + 1
                            else
                                sys.wait(10)
                            end    
                        end
                    end
                    i3=i3+1
                end
                i2=i2+1
            end
            i1=i1+1
        end
    end
end)

local button_timer_outtime = 10 --按键定时器: 10ms
local button_shake_time = 1     --按键消抖时间: button_shake_time*button_timer_outtime
local button_long_time = 100    --按键长按时间: button_shake_time*button_timer_outtime
local button_state = 0          --按键状态（松开0，按下1）
local button_cont = 0

local count_state = false        --s是否处在两次按下间计数状态
local button_cont_release = 0    
local button_release_time = 20    --最长连按时间: button_release_time*button_timer_outtime

button = gpio.setup(pin.PA00,	--button获取电平的闭包，button()表示状态
function() end,						--中断模式
gpio.PULLUP,gpio.FALLING)  --按键按下接地，因此需要上拉

sys.taskInit(function()
    while 1 do
		if button() == 0 then   --按键当前时刻为低电平（被按下） 此处根据上下拉选择0/1
			button_cont = button_cont + 1   --计数值加一
			if button_cont > button_long_time then  --计数次数大于长按阈值
				rs = true
			end
		else --按键当前时刻电平与状态不符
			if button_cont < button_shake_time then  --计数次数小于抖动阈值（视为抖动）
                if button_cont_release > button_release_time then
                    button_cont_release = 0
                    count_state = false
                    cs = not cs     --正常按键情况
                end
			else
				if button_cont < button_long_time then  --计数次数小于长按阈值
                    if button_cont_release <= button_release_time and count_state == true then
                        button_cont_release = 0
                        ss = true     --按键连按情况
                        cs = false
                    end
                    count_state = not count_state
				else
					rs = true  --长按情况
				end
			end
			button_cont = 0   --计数清零
			button_state = 0  --松开状态
            if button_cont_release <= button_release_time and count_state == true then
                button_cont_release = button_cont_release + 1   --松开计算值加一
            end
		end
		sys.wait(button_timer_outtime)
    end
end)
]]--
----------------------------ADKeyboard实验------------------------------
--接线：PB00 <-> VCC    PA01 <-> OUT
--PB00 -> PWM0  PA01 -> ADC0  因为ADC最大运行电压为2.4V，所以这里用PWM输出
--PWM0 10000Hz 占空比为66%时  未按下2125(2.125)V
--K1~K5 0 270 655 1024 1522
local adc_key_val = {150, 500, 850, 1300, 2000}
local NUM_KEYS = 5
local adc_key_in
local key=0
local oldkey=0

local function get_key(input)
    local k = 1
    while k <= NUM_KEYS do               --lua用while比for好点
        if input<adc_key_val[k] then
            return k
        end
        k=k+1
    end
    if k>NUM_KEYS then
        k=0
    end
    return k
end

sys.taskInit(function()
    pwm.open(0, 10000, 66) -- 频率10000hz, 占空比66
    adc.open(0)  --PA1
    sys.wait(100)
    while 1 do
        _,adc_key_in = adc.read(0)
        --log.info("adc", adc_key_in)
        key=get_key(adc_key_in)
        if key ~= oldkey then
            oldkey=key
            if key>=1 then
                if key == 1 then
                    log.info("S1 OK")
                elseif key == 2 then
                    log.info("S2 OK")
                elseif key == 3 then
                    log.info("S3 OK")
                elseif key == 4 then
                    log.info("S4 OK")
                elseif key == 5 then
                    log.info("S5 OK")
                end
            end
        end
        sys.wait(100)
    end
end)
------------------------------PWM捕获-----------------------------------

sys.run()


----------------------------学习笔记------------------------------------
--[[
    sys.timerLoopStart(fnc,ms,...)   开启一个循环定时器

    传入值类型  释义
    param      fnc定时器回调函数
    number     ms整数，最大定时126322567ms
    param      ...可变整数fnc的参数

    返回值
    number    定时器ID，如果失败，返回nil
------------------------------------------------------------------------
    pack - 打包和解包格式串
    --https://wiki.luatos.com/api/pack.html?highlight=pack
    --local _, data1, data2, data3, data4, data5, data6 = pack.unpack(data, "b6")
--]]
